home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume16 / deliver / part03 < prev    next >
Encoding:
Internet Message Format  |  1988-11-14  |  33.4 KB

  1. Subject:  v16i083:  Mail delivery program, Part03/03
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: Chip Salzenberg <chip@ateng.uu.net>
  6. Posting-number: Volume 16, Issue 83
  7. Archive-name: deliver/part03
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of shell archive."
  16. # Contents:  main.c mbox.c procs.c subs.c sysdep.c uucp.c
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f 'main.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'main.c'\"
  20. else
  21. echo shar: Extracting \"'main.c'\" \(9621 characters\)
  22. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  23. X/* $Header: main.c,v 1.5 88/09/14 20:00:03 network Exp $
  24. X *
  25. X * A program to deliver local mail with some flexibility.
  26. X *
  27. X * $Log:    main.c,v $
  28. X * Revision 1.5  88/09/14  20:00:03  network
  29. X * Add version string, including patchlevel.
  30. X * 
  31. X * Revision 1.4  88/09/14  19:41:54  network
  32. X * Portability to System V and BSD.
  33. X * General fixup.
  34. X * 
  35. X * Revision 1.3  88/08/30  16:13:54  network
  36. X * Remove general subroutines to new module, subs.c.
  37. X * 
  38. X * Revision 1.2  88/08/25  15:29:59  network
  39. X * Implement -s and -u options and ENV_SYSDEL and ENV_USERDEL environment
  40. X * variables.  Tighten up control over effective and real uid/gid.
  41. X * In particular, renounce setuid privileges if the system or user delivery
  42. X * file is specified.
  43. X * 
  44. X * Revision 1.1  88/06/06  09:38:54  chip
  45. X * Initial revision
  46. X * 
  47. X */
  48. X
  49. X#include "deliver.h"
  50. X#include "patchlevel.h"
  51. X#include <signal.h>
  52. X
  53. X/*
  54. X * External data.
  55. X */
  56. X
  57. X/* Variables set by getopt() [blech] */
  58. X
  59. Xextern  int     optind, opterr;
  60. Xextern  char    *optarg;
  61. X
  62. X/*
  63. X * Global data
  64. X */
  65. X
  66. Xint     verbose         = FALSE;
  67. Xint     dryrun          = FALSE;
  68. Xint     printaddrs      = FALSE;
  69. Xint     leavetemps      = FALSE;
  70. Xint     boxdelivery     = FALSE;
  71. X
  72. Xchar    *progname       = "deliver";
  73. Xchar    version[32]     = "1.0";
  74. Xchar    *shell          = SHELL;
  75. X
  76. Xchar    *sys_deliver    = NULL;
  77. Xchar    *user_deliver   = NULL;
  78. Xchar    *sender         = NULL;
  79. Xchar    *hostname       = NULL;
  80. X
  81. Xint     eff_uid         = -1;
  82. Xint     eff_gid         = -1;
  83. Xint     real_uid        = -1;
  84. Xint     real_gid        = -1;
  85. X
  86. XCONTEXT *eff_ct         = NULL;
  87. XCONTEXT *real_ct        = NULL;
  88. X
  89. Xchar    *ttype[T_MAX]   = { "header", "body" };
  90. Xchar    *tfile[T_MAX]   = { NULL, NULL };
  91. Xint     tfd[T_MAX]      = { -1, -1 };
  92. X
  93. X/*----------------------------------------------------------------------
  94. X * The Program.
  95. X */
  96. X
  97. Xmain(argc, argv)
  98. Xint     argc;
  99. Xchar    **argv;
  100. X{
  101. X    char    *p;
  102. X    int     u, c, errcount, insecure;
  103. X
  104. X    /* Make sure that stdout and stderr are interleaved correctly */
  105. X
  106. X    (void) Linebuf(stdout);
  107. X    (void) Linebuf(stderr);
  108. X
  109. X    /* Figure out the name used to invoke this program. */
  110. X
  111. X    progname = basename(argv[0]);
  112. X
  113. X    /* What version of the program is this? */
  114. X
  115. X    sprintf(version + strlen(version), ".%02d", PATCHLEVEL);
  116. X
  117. X    /* Figure out the name of this host */
  118. X
  119. X    if ((hostname = gethost()) == NULL)
  120. X    {
  121. X        hostname = "unknown";
  122. X        error("unable to determine host name; using \"%s\"\n",
  123. X              hostname);
  124. X    }
  125. X
  126. X    /* Process environment: handle recursive invocation */
  127. X
  128. X    if ((p = getenv(ENV_DFLAGS)) != NULL)
  129. X    {
  130. X        while (*p)
  131. X        {
  132. X            switch (*p++)
  133. X            {
  134. X            case 'v':
  135. X                verbose = TRUE;
  136. X                break;
  137. X            case 'd':
  138. X                verbose = TRUE;
  139. X                dryrun = TRUE;
  140. X                break;
  141. X            case 'A':
  142. X                printaddrs = TRUE;
  143. X                dryrun = TRUE;
  144. X                break;
  145. X            case 't':
  146. X                leavetemps = TRUE;
  147. X                break;
  148. X            }
  149. X        }
  150. X    }
  151. X    if ((p = getenv(ENV_SYSDEL)) != NULL)
  152. X        sys_deliver = p;
  153. X    if ((p = getenv(ENV_USERDEL)) != NULL)
  154. X        user_deliver = p;
  155. X    if ((p = getenv(ENV_SENDER)) != NULL)
  156. X        sender = p;
  157. X    if ((p = getenv(ENV_HOSTNAME)) != NULL)
  158. X        hostname = p;
  159. X
  160. X    /* Parse command line arguments */
  161. X
  162. X    while ((c = getopt(argc, argv, "vdAtbs:u:r:h:")) != EOF)
  163. X    {
  164. X        switch (c)
  165. X        {
  166. X        case 'v':
  167. X            verbose = TRUE;
  168. X            break;
  169. X        case 'd':
  170. X            verbose = TRUE;
  171. X            dryrun = TRUE;
  172. X            break;
  173. X        case 'A':
  174. X            printaddrs = TRUE;
  175. X            dryrun = TRUE;
  176. X            break;
  177. X        case 't':
  178. X            leavetemps = TRUE;
  179. X            break;
  180. X        case 'b':
  181. X            boxdelivery = TRUE;
  182. X            break;
  183. X        case 's':
  184. X            sys_deliver = optarg;
  185. X            break;
  186. X        case 'u':
  187. X            user_deliver = optarg;
  188. X            break;
  189. X        case 'r':
  190. X            sender = optarg;
  191. X            break;
  192. X        case 'h':
  193. X            hostname = optarg;
  194. X            break;
  195. X        case '?':
  196. X            usage();
  197. X        }
  198. X    }
  199. X
  200. X    /* If no destinations were given, forget it. */
  201. X
  202. X    if (optind >= argc)
  203. X    {
  204. X        message("%s: no recipients specified\n", progname);
  205. X        usage();
  206. X    }
  207. X
  208. X    /* Print a debugging message */
  209. X
  210. X    if (verbose)
  211. X    {
  212. X        message("%s %s running on host %s\n",
  213. X            progname, version, hostname);
  214. X        if (sender && *sender)
  215. X            message("Sender is %s\n", sender);
  216. X    }
  217. X
  218. X    /* Find effective and real uids and gids. */
  219. X
  220. X    eff_uid = geteuid();
  221. X    eff_gid = getegid();
  222. X    real_uid = getuid();
  223. X    real_gid = getgid();
  224. X
  225. X    if (eff_uid != real_uid && eff_uid != 0)
  226. X    {
  227. X        message("%s: if setuid, must be setuid root\n");
  228. X        leave(1);
  229. X    }
  230. X
  231. X    /* Renounce special privileges if something insecure was requested. */
  232. X
  233. X    if (sys_deliver || user_deliver)
  234. X    {
  235. X        if (setgid(eff_gid = real_gid) == -1
  236. X         || setuid(eff_uid = real_uid) == -1)
  237. X        {
  238. X            syserr("%s: can't renounce setuid privileges");
  239. X            leave(1);
  240. X        }
  241. X    }
  242. X
  243. X    /* Get the contexts of our effective and real uids. */
  244. X
  245. X    if ((eff_ct = uid_context(eff_uid)) == NULL)
  246. X        error("invalid effective uid %d!?\n", eff_uid);
  247. X
  248. X    if ((real_ct = uid_context(real_uid)) == NULL)
  249. X        error("invalid real uid %d!?\n", real_uid);
  250. X
  251. X    if (!eff_ct || !real_ct)
  252. X        leave(1);
  253. X
  254. X    if (verbose)
  255. X    {
  256. X        message("effective uid = %s (%d/%d); real uid = %s (%d/%d)\n",
  257. X            eff_ct->name, eff_ct->uid, eff_ct->gid,
  258. X            real_ct->name, real_ct->uid, real_ct->gid);
  259. X    }
  260. X
  261. X    /* Let's be sane about the file creation mask. */
  262. X
  263. X    u = umask(0);
  264. X    u &= ~0700;     /* Let's not deprive ourselves of permissions.  */
  265. X    u |= 022;       /* Let's be reasonably paranoid about writing.  */
  266. X    (void) umask(u);
  267. X
  268. X    /* Turn off all intrusive signals (unless we're not delivering). */
  269. X
  270. X    if (! dryrun)
  271. X    {
  272. X        (void) signal(SIGHUP, SIG_IGN);
  273. X        (void) signal(SIGINT, SIG_IGN);
  274. X        (void) signal(SIGQUIT, SIG_IGN);
  275. X    }
  276. X
  277. X    /*
  278. X     * Create the temporary files and write the message to them.
  279. X     */
  280. X
  281. X    if (copy_message() < 0)
  282. X        leave(1);
  283. X
  284. X    /*
  285. X     * Set up useful environment variables.
  286. X     * Note that this must be done _after_ copy_message(),
  287. X     * since that's where the temp files are created.
  288. X     */
  289. X
  290. X    setup_environ();
  291. X
  292. X    /*
  293. X     * Assign the default delivery file names.
  294. X     * Note that this must be after setup_environ(), or else the
  295. X     * environment won't reflect specified/unspecified options.
  296. X     */
  297. X
  298. X    if (!sys_deliver)
  299. X        sys_deliver = SYS_DELIVER;
  300. X    if (!user_deliver)
  301. X        user_deliver = USER_DELIVER;
  302. X
  303. X    /*
  304. X     * Perhaps we should consider all arguments as mailbox names...
  305. X     */
  306. X
  307. X    if (boxdelivery)
  308. X    {
  309. X        int     a;
  310. X
  311. X        if (verbose)
  312. X            message("mailbox delivery as %s\n", real_ct->name);
  313. X
  314. X        /*
  315. X         * Consider all arguments as mailbox filenames.
  316. X         */
  317. X
  318. X        for (a = optind; a < argc; ++a)
  319. X            (void) dest(real_ct->name, argv[a]);
  320. X
  321. X        if (verbose)
  322. X            dumpdests("(should all be mailboxes)");
  323. X    }
  324. X
  325. X    /*
  326. X     * They're not mailbox names, so they should be mail addresses.
  327. X     */
  328. X
  329. X    else
  330. X    {
  331. X        /*
  332. X         * Run all destinations though the system delivery file.
  333. X         * If sys_dfile() doesn't find one, it will call dest()
  334. X         * on each address.
  335. X         */
  336. X
  337. X        sys_dfile(argc - optind, argv + optind);
  338. X
  339. X        if (verbose)
  340. X            dumpdests("after running system delivery file");
  341. X
  342. X        /*
  343. X         * Run each user destination through his delivery file.
  344. X         */
  345. X
  346. X        user_dfiles();
  347. X
  348. X        if (verbose)
  349. X            dumpdests("after running user delivery files");
  350. X    }
  351. X
  352. X    /*
  353. X     * Drop mail in mailbox(es).
  354. X     */
  355. X
  356. X    mbox_deliver();
  357. X
  358. X    if (verbose)
  359. X        dumpdests("after delivery to all mailboxes");
  360. X
  361. X    /*
  362. X     * Send mail to UUCP address(es).
  363. X     */
  364. X
  365. X    uucp_deliver();
  366. X
  367. X    if (verbose)
  368. X        dumpdests("after delivery to UUCP addresses");
  369. X
  370. X    /*
  371. X     * Report any errors, and leave.
  372. X     */
  373. X
  374. X    errcount = report_errors();
  375. X
  376. X    /*
  377. X     * All done.
  378. X     */
  379. X
  380. X    leave(errcount ? 1 : 0);
  381. X    /* NOTREACHED */
  382. X}
  383. X
  384. X/*----------------------------------------------------------------------
  385. X * Print a usage message and exit.
  386. X */
  387. X
  388. Xusage()
  389. X{
  390. X    message("Usage: %s [-b][-A][-d][-v][-t][-r from][-h host] args\n", progname);
  391. X    message("-b      All arguments are mailbox filenames.\n");
  392. X    message("        (Default: arguments are user names.)\n");
  393. X    message("-A      Resolve addresses but do not deliver.\n");
  394. X    message("-d      Be verbose but do not deliver.\n");
  395. X    message("-v      Be verbose and deliver.\n");
  396. X    message("-t      Do not remote temp files before exiting.\n");
  397. X    message("-r from Specify the address to appear in the \"From \" line.\n");
  398. X    message("-h host Specify the host name.\n");
  399. X    message("        (This option overrides any \"From \" line in the input.)\n");
  400. X    message("args    Either user addresses or mailboxes (-b).\n");
  401. X    leave(1);
  402. X}
  403. X
  404. X/*----------------------------------------------------------------------
  405. X * Clean up and exit.
  406. X */
  407. X
  408. Xleave(code)
  409. Xint     code;
  410. X{
  411. X    if (! leavetemps)
  412. X    {
  413. X        int     t;
  414. X
  415. X        for (t = 0; t < T_MAX; ++t)
  416. X        {
  417. X            if (tfile[t] && unlink(tfile[t]) == -1)
  418. X                syserr("can't unlink %s", tfile[t]);
  419. X        }
  420. X    }
  421. X
  422. X    exit(code);
  423. X}
  424. X
  425. X/*----------------------------------------------------------------------
  426. X * Report any errors to stderr.
  427. X * Return an error count.
  428. X */
  429. X
  430. Xint
  431. Xreport_errors()
  432. X{
  433. X    DEST    *d;
  434. X    int     count = 0;
  435. X
  436. X    for (d = first_dest(); d; d = next_dest(d))
  437. X    {
  438. X        if (d->state != ST_ERROR)
  439. X            continue;
  440. X
  441. X        if (++count == 1)
  442. X        {
  443. X            error(
  444. X            "delivery to the following address(es) failed on host %s\n",
  445. X                hostname);
  446. X        }
  447. X
  448. X        message("\tuser \"%s\"", d->name);
  449. X        if (d->class == CL_MBOX)
  450. X            message(", mailbox \"%s\"", d->mailbox);
  451. X        message(": %s\n", d->error);
  452. X    }
  453. X
  454. X    return count;
  455. X}
  456. X
  457. X/*----------------------------------------------------------------------
  458. X * Set up useful environment variables.
  459. X */
  460. X
  461. Xsetup_environ()
  462. X{
  463. X    char    flags[8];
  464. X    int     f = 0;
  465. X
  466. X    flags[f++] = '-';
  467. X    if (verbose)
  468. X        flags[f++] = (dryrun ? 'd' : 'v');
  469. X    if (printaddrs)
  470. X        flags[f++] = 'A';
  471. X    if (leavetemps)
  472. X        flags[f++] = 't';
  473. X    flags[f] = 0;
  474. X
  475. X    alloc_env(ENV_DFLAGS, (f > 1) ? flags : "");
  476. X    if (sys_deliver && *sys_deliver)
  477. X        alloc_env(ENV_SYSDEL, sys_deliver);
  478. X    if (user_deliver && *user_deliver)
  479. X        alloc_env(ENV_USERDEL, user_deliver);
  480. X    if (hostname && *hostname)
  481. X        alloc_env(ENV_HOSTNAME, hostname);
  482. X    if (sender && *sender)
  483. X        alloc_env(ENV_SENDER, sender);
  484. X
  485. X    alloc_env(ENV_HEADER, tfile[T_HEADER]);
  486. X    alloc_env(ENV_BODY,   tfile[T_BODY]);
  487. X
  488. X    alloc_env("IFS", " \t\n");
  489. X}
  490. END_OF_FILE
  491. if test 9621 -ne `wc -c <'main.c'`; then
  492.     echo shar: \"'main.c'\" unpacked with wrong size!
  493. fi
  494. # end of 'main.c'
  495. fi
  496. if test -f 'mbox.c' -a "${1}" != "-c" ; then 
  497.   echo shar: Will not clobber existing file \"'mbox.c'\"
  498. else
  499. echo shar: Extracting \"'mbox.c'\" \(4767 characters\)
  500. sed "s/^X//" >'mbox.c' <<'END_OF_FILE'
  501. X/* $Header: mbox.c,v 1.2 88/09/14 19:42:06 network Exp $
  502. X *
  503. X * Finally!  Put the message in the specified mailbox(es).
  504. X *
  505. X * $Log:    mbox.c,v $
  506. X * Revision 1.2  88/09/14  19:42:06  network
  507. X * Portability to System V and BSD.
  508. X * General fixup.
  509. X * 
  510. X * Revision 1.1  88/06/06  09:39:06  chip
  511. X * Initial revision
  512. X * 
  513. X */
  514. X
  515. X#include "deliver.h"
  516. X#include <sys/types.h>
  517. X#include <sys/stat.h>
  518. X#include <errno.h>
  519. X
  520. X/*
  521. X * External data.
  522. X */
  523. X
  524. Xextern  int     errno;
  525. X
  526. X/*
  527. X * Local functions.
  528. X */
  529. X
  530. Xstatic          mbox_dest();
  531. Xstatic  int     mbox_write();
  532. Xstatic  int     mbox_copy();
  533. X
  534. X/*----------------------------------------------------------------------
  535. X * Deliver mail to all valid destinations.
  536. X */
  537. X
  538. Xmbox_deliver()
  539. X{
  540. X    DEST    *d;
  541. X
  542. X    for (d = first_dest(); d; d = next_dest(d))
  543. X    {
  544. X        switch (d->class)
  545. X        {
  546. X        case CL_USER:
  547. X        case CL_MBOX:
  548. X            if (d->state == ST_WORKING)
  549. X                mbox_dest(d);
  550. X            break;
  551. X        }
  552. X    }
  553. X}
  554. X
  555. X/*----------------------------------------------------------------------
  556. X * Deliver mail to one destination.
  557. X */
  558. X
  559. Xstatic
  560. Xmbox_dest(d)
  561. XDEST    *d;
  562. X{
  563. X    CONTEXT *ct;
  564. X    int     ret = 0;
  565. X
  566. X    if (printaddrs)
  567. X    {
  568. X        (void) printf("%s", d->name);
  569. X        if (d->class == CL_MBOX)
  570. X            (void) printf(":%s", d->mailbox);
  571. X        (void) printf("\n");
  572. X    }
  573. X
  574. X    if (dryrun)
  575. X    {
  576. X        d->state = ST_DONE;
  577. X        return;
  578. X    }
  579. X
  580. X    if ((ct = name_context(d->name)) == NULL)
  581. X    {
  582. X        d->state = ST_ERROR;
  583. X        d->error = "Lost context in mbox_dest()";
  584. X        return;
  585. X    }
  586. X
  587. X    if (! ok_context(ct))
  588. X    {
  589. X        d->state = ST_ERROR;
  590. X        d->error = "No permissions for that context";
  591. X        return;
  592. X    }
  593. X
  594. X    if (d->class == CL_MBOX)
  595. X    {
  596. X        give_temps(ct);
  597. X
  598. X        if (sfork() == 0)
  599. X        {
  600. X            if (become(ct, !boxdelivery) < 0)
  601. X                exit(1);
  602. X            if (mbox_write(d->mailbox, ct, FALSE) < 0)
  603. X                exit(1);
  604. X            exit(0);
  605. X        }
  606. X
  607. X        if (await_child() != 0)
  608. X            ret = -1;
  609. X    }
  610. X    else
  611. X    {
  612. X        char    mailbox[100];
  613. X
  614. X        (void) sprintf(mailbox, "%s/%s",
  615. X#ifdef MAILBOX_DIR
  616. X            MAILBOX_DIR, d->name
  617. X#else
  618. X            d->home, MAILBOX_NAME
  619. X#endif
  620. X            );
  621. X
  622. X        if (mbox_write(mailbox, ct, TRUE) < 0)
  623. X            ret = -1;
  624. X    }
  625. X
  626. X    if (ret >= 0)
  627. X        d->state = ST_DONE;
  628. X    else
  629. X    {
  630. X        d->state = ST_ERROR;
  631. X        d->error = "Error writing to mailbox";
  632. X    }
  633. X}
  634. X
  635. X/*----------------------------------------------------------------------
  636. X * Write mail to the named mailbox.
  637. X * If we have to create the mailbox, give it to the specified user.
  638. X * If "is_sys" is true, then we're writing to a system mailbox.
  639. X */
  640. X
  641. Xstatic int
  642. Xmbox_write(mailbox, ct, is_sys)
  643. Xchar    *mailbox;
  644. XCONTEXT *ct;
  645. Xint     is_sys;
  646. X{
  647. X    int     fd, t;
  648. X    int     ret = 0;
  649. X
  650. X    if (verbose)
  651. X    {
  652. X        message("As %s, delivering to %s mailbox %s\n",
  653. X            ct->name, (is_sys ? "system" : "user"), mailbox);
  654. X    }
  655. X
  656. X    if (lock_name(mailbox) < 0)
  657. X        return -1;
  658. X
  659. X    while ((fd = open(mailbox, O_RDWR)) == -1)
  660. X    {
  661. X        if (errno != ENOENT)
  662. X        {
  663. X            syserr("can't open %s", mailbox);
  664. X            break;
  665. X        }
  666. X
  667. X        if ((fd = open(mailbox, O_RDWR|O_CREAT|O_EXCL,
  668. X                MAILBOX_MODE)) != -1)
  669. X        {
  670. X            /* Make sure the mailbox receives the correct modes */
  671. X
  672. X            int mbox_gid = ct->gid;
  673. X
  674. X#ifdef MAILBOX_GROUP
  675. X            if (is_sys)
  676. X            {
  677. X                static int mbox_gid_sv = -2;
  678. X
  679. X                if (mbox_gid_sv == -2)
  680. X                    mbox_gid_sv = group_id(MAILBOX_GROUP);
  681. X
  682. X                if (mbox_gid_sv < 0)
  683. X                    message("%s: no such group\n", MAILBOX_GROUP);
  684. X                else
  685. X                    mbox_gid = mbox_gid_sv;
  686. X            }
  687. X#endif /* MAILBOX_GROUP */
  688. X
  689. X            if (chown(mailbox, ct->uid, mbox_gid) == -1)
  690. X            {
  691. X                /* print a message, but that's all. (???) */
  692. X                syserr("can't chown %s to %d,%d",
  693. X                    mailbox, ct->uid, mbox_gid);
  694. X            }
  695. X            break;
  696. X        }
  697. X
  698. X        if (errno != EEXIST)
  699. X        {
  700. X            syserr("can't create %s", mailbox);
  701. X            break;
  702. X        }
  703. X    }
  704. X
  705. X    if (fd == -1)
  706. X    {
  707. X        (void) unlock_name(mailbox);
  708. X        return -1;
  709. X    }
  710. X
  711. X    if (lock_fd(fd) < 0)
  712. X    {
  713. X        (void) close(fd);
  714. X        (void) unlock_name(mailbox);
  715. X        return -1;
  716. X    }
  717. X
  718. X    (void) lseek(fd, 0L, 2); /* No error check: may be a special file */
  719. X
  720. X    for (t = 0; t < T_MAX; ++t)
  721. X    {
  722. X        if (lseek(tfd[t], 0L, 0) == -1)
  723. X        {
  724. X            syserr("lseek in %s file %s", ttype[t], tfile[t]);
  725. X            ret = -1;
  726. X            break;
  727. X        }
  728. X
  729. X        switch (mbox_copy(tfd[t], fd))
  730. X        {
  731. X        case 1:
  732. X            syserr("can't read %s file %s", ttype[t], tfile[t]);
  733. X            ret = -1;
  734. X            break;
  735. X        case 2:
  736. X            syserr("can't write to mailbox %s as %s",
  737. X                mailbox, ct->name);
  738. X            ret = -1;
  739. X            break;
  740. X        default:
  741. X            continue;
  742. X        }
  743. X        break;
  744. X    }
  745. X
  746. X    if (verbose)
  747. X    {
  748. X        if (ret >= 0)
  749. X            message("wrote message to %s\n", mailbox);
  750. X    }
  751. X
  752. X    if (unlock_fd(fd) < 0)
  753. X        ret = -1;
  754. X    (void) close(fd);
  755. X    if (unlock_name(mailbox) < 0)
  756. X        ret = -1;
  757. X
  758. X    return ret;
  759. X}
  760. X
  761. X/*----------------------------------------------------------------------
  762. X * Copy the named file to the given file descriptor.
  763. X */
  764. X
  765. Xstatic int
  766. Xmbox_copy(ifd, ofd)
  767. Xint     ifd;
  768. Xint     ofd;
  769. X{
  770. X    char    buf[BUFSIZ];
  771. X    int     rd;
  772. X
  773. X    while ((rd = read(ifd, buf, sizeof(buf))) > 0)
  774. X    {
  775. X        errno = 255;    /* to avoid bogus syserr() output */
  776. X        if (write(ofd, buf, (unsigned) rd) != rd)
  777. X            return 2;
  778. X    }
  779. X
  780. X    if (rd == -1)
  781. X        return 1;
  782. X
  783. X    return 0;
  784. X}
  785. END_OF_FILE
  786. if test 4767 -ne `wc -c <'mbox.c'`; then
  787.     echo shar: \"'mbox.c'\" unpacked with wrong size!
  788. fi
  789. # end of 'mbox.c'
  790. fi
  791. if test -f 'procs.c' -a "${1}" != "-c" ; then 
  792.   echo shar: Will not clobber existing file \"'procs.c'\"
  793. else
  794. echo shar: Extracting \"'procs.c'\" \(5021 characters\)
  795. sed "s/^X//" >'procs.c' <<'END_OF_FILE'
  796. X/* $Header: procs.c,v 1.2 88/09/14 19:42:28 network Exp $
  797. X *
  798. X * Process management and misc support.
  799. X *
  800. X * $Log:    procs.c,v $
  801. X * Revision 1.2  88/09/14  19:42:28  network
  802. X * Portability to System V and BSD.
  803. X * General fixup.
  804. X * 
  805. X * Revision 1.1  88/06/06  09:39:15  chip
  806. X * Initial revision
  807. X * 
  808. X */
  809. X
  810. X#include "deliver.h"
  811. X#include <errno.h>
  812. X#include <signal.h>
  813. X
  814. X/*
  815. X * External data.
  816. X */
  817. X
  818. Xextern  int     errno;
  819. X
  820. X/*
  821. X * Local data.
  822. X */
  823. X
  824. Xstatic  int     child_pid = -1;
  825. Xstatic  int     (*saved_sigpipe)() = SIG_DFL;
  826. X
  827. X/*----------------------------------------------------------------------
  828. X * Like popen(), but execute the child in a specific context.
  829. X * Also, the argument list is already a vector.
  830. X */
  831. X
  832. XFILE *
  833. Xct_popenv(ct, prog, av, mode)
  834. XCONTEXT *ct;
  835. Xchar    *prog;
  836. Xchar    **av;
  837. Xchar    *mode;
  838. X{
  839. X    char    ch;
  840. X    int     child, parent;
  841. X    int     pfd[2];
  842. X
  843. X    if (!ct || !prog || !av || !mode)
  844. X        return NULL;
  845. X
  846. X    if (mode[0] == 'r' && mode[1] == 0)
  847. X        child = 1, parent = 0;
  848. X    else if (mode[0] == 'w' && mode[1] == 0)
  849. X        child = 0, parent = 1;
  850. X    else
  851. X        return NULL;
  852. X
  853. X    /* We can't have more than one child at a time. */
  854. X
  855. X    if (child_pid >= 0)
  856. X    {
  857. X        error("in ct_popen: a process is already open\n");
  858. X        return NULL;
  859. X    }
  860. X
  861. X    /* Make a stab at predicting uid-related failure. */
  862. X
  863. X    if (! ok_context(ct))
  864. X    {
  865. X        error("in ct_popen: no permissions to become %s\n", ct->name);
  866. X        return NULL;
  867. X    }
  868. X
  869. X    /* Pipes?  Like, tubular, fer shur! */
  870. X
  871. X    if (pipe(pfd) == -1)
  872. X    {
  873. X        syserr("can't create a pipe");
  874. X        return NULL;
  875. X    }
  876. X
  877. X    /* Generate a debugging message. */
  878. X
  879. X    if (verbose)
  880. X    {
  881. X        int a;
  882. X
  883. X        message("Spawning");
  884. X        for (a = 0; av[a]; ++a)
  885. X            message(" %s", av[a]);
  886. X        message("\n");
  887. X    }
  888. X
  889. X    /* Handle the child case */
  890. X
  891. X    if (sfork() == 0)
  892. X    {
  893. X        if (child == 0)
  894. X        {
  895. X            (void) close(0);
  896. X            (void) dup(pfd[0]);     /* ass_u_me 0 */
  897. X        }
  898. X        else
  899. X        {
  900. X            (void) close(0);
  901. X            if (open("/dev/null", O_RDONLY) != 0)
  902. X            {
  903. X                /* This should _never_ happen, but... */
  904. X                syserr("can't open /dev/null");
  905. X                (void) dup(1);  /* ass_u_me 0 */
  906. X            }
  907. X
  908. X            (void) close(1);
  909. X            (void) dup(pfd[1]);     /* ass_u_me 1 */
  910. X        }
  911. X
  912. X        if (become(ct, TRUE) < 0)
  913. X            (void) write(pfd[1], "n", 1);
  914. X        else
  915. X        {
  916. X            int     t;
  917. X
  918. X            (void) write(pfd[1], "y", 1);
  919. X
  920. X            (void) close(pfd[child]);
  921. X            (void) close(pfd[parent]);
  922. X            for (t = 0; t < T_MAX; ++t)
  923. X                (void) close(tfd[t]);
  924. X
  925. X            (void) execv(prog, av);
  926. X            syserr("can't execute %s", prog);
  927. X        }
  928. X
  929. X        exit(127);
  930. X    }
  931. X
  932. X    /* Make sure that a broken pipe won't kill us */
  933. X
  934. X    saved_sigpipe = signal(SIGPIPE, SIG_IGN);
  935. X
  936. X    /* The child must report "OK" before we continue. */
  937. X
  938. X    if ((read(pfd[0], &ch, 1) < 1) || (ch != 'y'))
  939. X    {
  940. X        (void) close(pfd[0]);
  941. X        (void) close(pfd[1]);
  942. X        (void) await_child();
  943. X        return NULL;
  944. X    }
  945. X
  946. X    (void) close(pfd[child]);
  947. X    return fdopen(pfd[parent], mode);
  948. X}
  949. X
  950. X/*----------------------------------------------------------------------
  951. X * Close the stream opened by ct_popen().
  952. X */
  953. X
  954. Xct_pclose(fp)
  955. XFILE    *fp;
  956. X{
  957. X    if (fp)
  958. X        (void) fclose(fp);
  959. X    return await_child();
  960. X}
  961. X
  962. X/*----------------------------------------------------------------------
  963. X * Assume the identity of the given user.
  964. X */
  965. X
  966. Xint
  967. Xbecome(ct, chd)
  968. XCONTEXT *ct;
  969. Xint     chd;
  970. X{
  971. X    char    env_path[32];
  972. X
  973. X    /*
  974. X     * Assume a new identity.
  975. X     * Note the importance of doing the setgid() before the setuid().
  976. X     */
  977. X
  978. X    if (setgid(ct->gid) == -1)
  979. X    {
  980. X        syserr("can't setgid to %d", ct->gid);
  981. X        return -1;
  982. X    }
  983. X    if (setuid(ct->uid) == -1)
  984. X    {
  985. X        syserr("can't setgid to %u", ct->uid);
  986. X        return -1;
  987. X    }
  988. X    if (chd && chdir(ct->home) == -1)
  989. X    {
  990. X        syserr("can't chdir to %s", ct->home);
  991. X        return -1;
  992. X    }
  993. X
  994. X    /* Set up the environment */
  995. X
  996. X    (void) sprintf(env_path, "%s:/bin:/usr/bin",
  997. X            ((ct->uid == 0) ? "/etc" : "."));
  998. X    alloc_env("HOME", ct->home);
  999. X    alloc_env("PATH", env_path);
  1000. X
  1001. X    /* I guess it worked. */
  1002. X
  1003. X    return 0;
  1004. X}
  1005. X
  1006. X/*----------------------------------------------------------------------
  1007. X * Safe fork.  If it doesn't work, it exits.
  1008. X */
  1009. X
  1010. Xint
  1011. Xsfork()
  1012. X{
  1013. X    int     tries;
  1014. X
  1015. X    /*
  1016. X     * A few safety measures.
  1017. X     */
  1018. X
  1019. X    (void) await_child();
  1020. X    (void) fflush(stdout);
  1021. X    (void) fflush(stderr);
  1022. X
  1023. X    /*
  1024. X     * Be patient in waiting for a fork().
  1025. X     */
  1026. X
  1027. X    for (tries = 0; tries < 10; ++tries)
  1028. X    {
  1029. X        if (tries)
  1030. X            snooze(3);
  1031. X        if ((child_pid = fork()) >= 0)
  1032. X            return child_pid;
  1033. X        if (errno != EAGAIN)
  1034. X            break;
  1035. X    }
  1036. X
  1037. X    syserr("can't fork");
  1038. X    leave(1);
  1039. X    /* NOTREACHED */
  1040. X}
  1041. X
  1042. X/*----------------------------------------------------------------------
  1043. X * Wait for our child (if any) to exit.
  1044. X * Returns child's exit status or -1 if there is a problem.
  1045. X */
  1046. X
  1047. Xint
  1048. Xawait_child()
  1049. X{
  1050. X    int     wpid, st;
  1051. X
  1052. X    if (child_pid < 0)
  1053. X        return -1;
  1054. X
  1055. X    while ((wpid = wait(&st)) >= 0)
  1056. X    {
  1057. X        if (wpid == child_pid)
  1058. X            break;
  1059. X    }
  1060. X
  1061. X    child_pid = -1;
  1062. X    if (wpid == -1)
  1063. X        syserr("waiting for child");
  1064. X
  1065. X    (void) signal(SIGPIPE, saved_sigpipe);
  1066. X    saved_sigpipe = SIG_DFL;
  1067. X
  1068. X    if (wpid == -1)
  1069. X        return -1;
  1070. X
  1071. X    if (st & 0xFF)
  1072. X    {
  1073. X        error("child process died%s due to signal %d.\n",
  1074. X            ((st & 0x80) ? " and dumped core" : ""),
  1075. X            (st & 0x7F));
  1076. X
  1077. X        return -1;
  1078. X    }
  1079. X
  1080. X    if (verbose)
  1081. X    {
  1082. X        message("child process exited with status %d.\n",
  1083. X            (st >> 8) & 0xFF);
  1084. X    }
  1085. X
  1086. X    return ((st >> 8) & 0xFF);
  1087. X}
  1088. END_OF_FILE
  1089. if test 5021 -ne `wc -c <'procs.c'`; then
  1090.     echo shar: \"'procs.c'\" unpacked with wrong size!
  1091. fi
  1092. # end of 'procs.c'
  1093. fi
  1094. if test -f 'subs.c' -a "${1}" != "-c" ; then 
  1095.   echo shar: Will not clobber existing file \"'subs.c'\"
  1096. else
  1097. echo shar: Extracting \"'subs.c'\" \(2050 characters\)
  1098. sed "s/^X//" >'subs.c' <<'END_OF_FILE'
  1099. X/* $Header: subs.c,v 1.3 88/09/14 19:42:33 network Exp $
  1100. X *
  1101. X * Miscellaneous subroutines.
  1102. X *
  1103. X * $Log:    subs.c,v $
  1104. X * Revision 1.3  88/09/14  19:42:33  network
  1105. X * Portability to System V and BSD.
  1106. X * General fixup.
  1107. X * 
  1108. X * Revision 1.2  88/08/30  16:14:53  network
  1109. X * New module.  Includes routines from main.c.
  1110. X * Also, new routine savestr().
  1111. X * 
  1112. X */
  1113. X
  1114. X#include "deliver.h"
  1115. X
  1116. X/*----------------------------------------------------------------------
  1117. X * Allocate memory for an environment variable, and putenv() it.
  1118. X */
  1119. X
  1120. Xalloc_env(name, value)
  1121. Xchar    *name;
  1122. Xchar    *value;
  1123. X{
  1124. X    char    *s;
  1125. X
  1126. X    if (!name || !value)
  1127. X        return;
  1128. X
  1129. X    s = zalloc((unsigned) (strlen(name) + strlen(value) + 2));
  1130. X    (void) sprintf(s, "%s=%s", name, value);
  1131. X    if (putenv(s))
  1132. X        nomem();
  1133. X}
  1134. X
  1135. X/*----------------------------------------------------------------------
  1136. X * Allocate and clear.  If it fails, it takes the emergency exit.
  1137. X */
  1138. X
  1139. Xchar *
  1140. Xzalloc(size)
  1141. Xunsigned size;
  1142. X{
  1143. X    char    *p;
  1144. X
  1145. X    if ((p = malloc(size)) == NULL)
  1146. X        nomem();
  1147. X
  1148. X    (void) Zero(p, size);
  1149. X    return p;
  1150. X}
  1151. X
  1152. X/*----------------------------------------------------------------------
  1153. X * Reallocate to new size.  If it fails, it takes the emergency exit.
  1154. X */
  1155. X
  1156. Xchar *
  1157. Xsrealloc(ptr, size)
  1158. Xchar    *ptr;
  1159. Xunsigned size;
  1160. X{
  1161. X    char    *p;
  1162. X
  1163. X    if ((p = realloc(ptr, size)) == NULL)
  1164. X        nomem();
  1165. X
  1166. X    return p;
  1167. X}
  1168. X
  1169. X/*----------------------------------------------------------------------
  1170. X * Make an allocated copy of a string.
  1171. X */
  1172. X
  1173. Xchar *
  1174. Xcopystr(s)
  1175. Xchar    *s;
  1176. X{
  1177. X    char    *p;
  1178. X
  1179. X    if (s == NULL)
  1180. X        return NULL;
  1181. X
  1182. X    if ((p = malloc((unsigned) strlen(s) + 1)) == NULL)
  1183. X        nomem();
  1184. X
  1185. X    (void) strcpy(p, s);
  1186. X    return p;
  1187. X}
  1188. X
  1189. X/*----------------------------------------------------------------------
  1190. X * Emergency exit for memory loss.
  1191. X */
  1192. X
  1193. Xnomem()
  1194. X{
  1195. X    message("%s: out of memory\n", progname);
  1196. X    leave(1);
  1197. X}
  1198. X
  1199. X/*----------------------------------------------------------------------
  1200. X * Return the last component of the given pathname.
  1201. X */
  1202. X
  1203. Xchar *
  1204. Xbasename(name)
  1205. Xchar    *name;
  1206. X{
  1207. X    char    *b;
  1208. X
  1209. X    if ((b = strrchr(name, '/')) != NULL)
  1210. X        ++b;
  1211. X    else
  1212. X        b = name;
  1213. X
  1214. X    return (b);
  1215. X}
  1216. END_OF_FILE
  1217. if test 2050 -ne `wc -c <'subs.c'`; then
  1218.     echo shar: \"'subs.c'\" unpacked with wrong size!
  1219. fi
  1220. # end of 'subs.c'
  1221. fi
  1222. if test -f 'sysdep.c' -a "${1}" != "-c" ; then 
  1223.   echo shar: Will not clobber existing file \"'sysdep.c'\"
  1224. else
  1225. echo shar: Extracting \"'sysdep.c'\" \(5242 characters\)
  1226. sed "s/^X//" >'sysdep.c' <<'END_OF_FILE'
  1227. X/* $Header: sysdep.c,v 1.3 88/09/14 20:00:24 network Exp $
  1228. X *
  1229. X * Routines which are (or might well be) system-dependant.
  1230. X * I've put the message routines here since you may need to use
  1231. X * the ANSI <stdarg.h> instead of <varargs.h>.
  1232. X *
  1233. X * $Log:    sysdep.c,v $
  1234. X * Revision 1.3  88/09/14  20:00:24  network
  1235. X * Fix type of gethostname() for BSD.
  1236. X * 
  1237. X * Revision 1.2  88/09/14  19:42:37  network
  1238. X * Portability to System V and BSD.
  1239. X * General fixup.
  1240. X * 
  1241. X * Revision 1.1  88/06/06  09:39:29  chip
  1242. X * Initial revision
  1243. X * 
  1244. X */
  1245. X
  1246. X#include "deliver.h"
  1247. X#include <errno.h>
  1248. X#include <varargs.h>
  1249. X
  1250. X#ifdef UNAME
  1251. X#include <sys/utsname.h>
  1252. X#endif
  1253. X
  1254. X/*
  1255. X * External functions.
  1256. X */
  1257. X
  1258. X#ifdef M_XENIX
  1259. Xextern  long    nap();
  1260. X#else
  1261. Xextern  unsigned sleep();
  1262. X#endif
  1263. X
  1264. X/*
  1265. X * External data.
  1266. X */
  1267. X
  1268. Xextern  int     errno;
  1269. Xextern  int     sys_nerr;
  1270. Xextern  char    *sys_errlist[];
  1271. X
  1272. X/*----------------------------------------------------------------------
  1273. X * Print a message.
  1274. X */
  1275. X
  1276. X/* VARARGS1 */
  1277. Xmessage(fmt, va_alist)
  1278. Xchar    *fmt;
  1279. Xva_dcl
  1280. X{
  1281. X    va_list args;
  1282. X    va_start(args);
  1283. X
  1284. X    (void) vfprintf(stderr, fmt, args);
  1285. X}
  1286. X
  1287. X/*----------------------------------------------------------------------
  1288. X * Print an error message.
  1289. X */
  1290. X
  1291. X/* VARARGS1 */
  1292. Xerror(fmt, va_alist)
  1293. Xchar    *fmt;
  1294. Xva_dcl
  1295. X{
  1296. X    va_list args;
  1297. X    va_start(args);
  1298. X
  1299. X    (void) fprintf(stderr, "%s: ", progname);
  1300. X    (void) vfprintf(stderr, fmt, args);
  1301. X}
  1302. X
  1303. X/*----------------------------------------------------------------------
  1304. X * Report an error returned from a system call.
  1305. X */
  1306. X
  1307. X/* VARARGS1 */
  1308. Xsyserr(fmt, va_alist)
  1309. Xchar    *fmt;
  1310. Xva_dcl
  1311. X{
  1312. X    int     e = errno;
  1313. X    va_list args;
  1314. X    va_start(args);
  1315. X
  1316. X    (void) fprintf(stderr, "%s: ", progname);
  1317. X    (void) vfprintf(stderr, fmt, args);
  1318. X    if (e <= sys_nerr)
  1319. X        (void) fprintf(stderr, ": %s\n", sys_errlist[e]);
  1320. X    else
  1321. X        (void) fprintf(stderr, ": unknown system error %d\n", e);
  1322. X}
  1323. X
  1324. X/*----------------------------------------------------------------------
  1325. X * Sleep for the given number of seconds.
  1326. X */
  1327. X
  1328. Xsnooze(n)
  1329. Xint     n;
  1330. X{
  1331. X#ifdef M_XENIX
  1332. X    (void) nap(n * 1000L);
  1333. X#else
  1334. X    (void) sleep(n);
  1335. X#endif
  1336. X}
  1337. X
  1338. X/*----------------------------------------------------------------------
  1339. X * Get the host name from HOSTFILE.
  1340. X */
  1341. X
  1342. X#ifdef HOSTFILE
  1343. X
  1344. Xchar *
  1345. Xgethost()
  1346. X{
  1347. X    int     fd, rd;
  1348. X    char    *p;
  1349. X    static char name[32];
  1350. X
  1351. X    if ((fd = open(HOSTFILE, O_RDONLY)) == -1)
  1352. X        return NULL;
  1353. X    rd = read(fd, name, sizeof(name) - 1);
  1354. X    (void) close(fd);
  1355. X
  1356. X    if (rd < 1)
  1357. X        return NULL;
  1358. X    name[rd] = 0;
  1359. X    if ((p = strchr(name, '\n')) != NULL)
  1360. X        *p = 0;
  1361. X
  1362. X    return (name[0] ? name : NULL);
  1363. X}
  1364. X
  1365. X#endif /* HOSTFILE */
  1366. X
  1367. X/*----------------------------------------------------------------------
  1368. X * Get the host name via the uname() system call.
  1369. X */
  1370. X
  1371. X#ifdef UNAME
  1372. X
  1373. Xchar *
  1374. Xgethost()
  1375. X{
  1376. X    static struct utsname u;
  1377. X
  1378. X    uname(&u);
  1379. X    return (u.nodename[0] ? u.nodename : NULL);
  1380. X}
  1381. X
  1382. X#endif /* UNAME */
  1383. X
  1384. X/*----------------------------------------------------------------------
  1385. X * Get the host name via the gethostname() system call.
  1386. X */
  1387. X
  1388. X#ifdef GETHOSTNAME
  1389. X
  1390. Xchar *
  1391. Xgethost()
  1392. X{
  1393. X    static char hostname[64];
  1394. X
  1395. X    if (gethostname(hostname, sizeof(hostname)) == -1)
  1396. X        return NULL;
  1397. X
  1398. X    return hostname;
  1399. X}
  1400. X
  1401. X#endif /* GETHOSTNAME */
  1402. X
  1403. X/*----------------------------------------------------------------------
  1404. X * Variable-argument-list output, System V style.
  1405. X */
  1406. X
  1407. X#ifndef HAS_VPRINTF
  1408. X
  1409. Xvprintf(fmt, ap)
  1410. Xchar    *fmt;
  1411. Xva_list ap;
  1412. X{
  1413. X    int     a,b,c,d,e,f,g,h;
  1414. X
  1415. X    a = va_arg(ap, int);
  1416. X    b = va_arg(ap, int);
  1417. X    c = va_arg(ap, int);
  1418. X    d = va_arg(ap, int);
  1419. X    e = va_arg(ap, int);
  1420. X    f = va_arg(ap, int);
  1421. X    g = va_arg(ap, int);
  1422. X    h = va_arg(ap, int);
  1423. X
  1424. X    printf(fmt, a,b,c,d,e,f,g,h);
  1425. X}
  1426. X
  1427. Xvfprintf(fp, fmt, ap)
  1428. XFILE    *fp;
  1429. Xchar    *fmt;
  1430. Xva_list ap;
  1431. X{
  1432. X    int     a,b,c,d,e,f,g,h;
  1433. X
  1434. X    a = va_arg(ap, int);
  1435. X    b = va_arg(ap, int);
  1436. X    c = va_arg(ap, int);
  1437. X    d = va_arg(ap, int);
  1438. X    e = va_arg(ap, int);
  1439. X    f = va_arg(ap, int);
  1440. X    g = va_arg(ap, int);
  1441. X    h = va_arg(ap, int);
  1442. X
  1443. X    fprintf(fp, fmt, a,b,c,d,e,f,g,h);
  1444. X}
  1445. X
  1446. Xvsprintf(s, fmt, ap)
  1447. Xchar    *s;
  1448. Xchar    *fmt;
  1449. Xva_list ap;
  1450. X{
  1451. X    int     a,b,c,d,e,f,g,h;
  1452. X
  1453. X    a = va_arg(ap, int);
  1454. X    b = va_arg(ap, int);
  1455. X    c = va_arg(ap, int);
  1456. X    d = va_arg(ap, int);
  1457. X    e = va_arg(ap, int);
  1458. X    f = va_arg(ap, int);
  1459. X    g = va_arg(ap, int);
  1460. X    h = va_arg(ap, int);
  1461. X
  1462. X    sprintf(s, fmt, a,b,c,d,e,f,g,h);
  1463. X}
  1464. X
  1465. X#endif  /* HAS_VPRINTF */
  1466. X
  1467. X/*----------------------------------------------------------------------
  1468. X * Add a new environment variable.
  1469. X */
  1470. X
  1471. X#ifndef HAS_PUTENV
  1472. X
  1473. Xint
  1474. Xputenv(s)
  1475. Xchar *s;
  1476. X{
  1477. X    static  char    **env_array;
  1478. X    static  int     env_size;
  1479. X    char    *e;
  1480. X    int     i, j;
  1481. X
  1482. X    if (env_array == NULL)
  1483. X    {
  1484. X        for (i = 0; environ[i]; ++i)
  1485. X            {}
  1486. X        env_size = i + 10;      /* arbitrary */
  1487. X        env_array = (char **) zalloc(env_size * sizeof(char *));
  1488. X        (void) memcpy((char *)env_array, (char *)environ,
  1489. X                (int) ((i + 1) * sizeof(char *)));
  1490. X        environ = env_array;
  1491. X    }
  1492. X    else if (environ != env_array)
  1493. X        message("putenv: warning: someone moved environ!\n");
  1494. X
  1495. X    if ((e = strchr(s, '=')) != NULL)
  1496. X        ++e;
  1497. X    else
  1498. X        e = s + strlen(s);
  1499. X
  1500. X    j = 0;
  1501. X    for (i = 0; env_array[i]; ++i)
  1502. X    {
  1503. X        if (strncmp(env_array[i], s, e - s) != 0)
  1504. X            env_array[j++] = env_array[i];
  1505. X    }
  1506. X
  1507. X    if ((j + 1) >= env_size)
  1508. X    {
  1509. X        env_size += 10;                 /* arbitrary */
  1510. X        env_array = (char **) srealloc((char *)env_array,
  1511. X                    env_size * sizeof(char **));
  1512. X    }
  1513. X
  1514. X    env_array[j++] = s;
  1515. X    env_array[j] = NULL;
  1516. X
  1517. X    environ = env_array;
  1518. X    return 0;
  1519. X}
  1520. X
  1521. X#endif  /* HAS_PUTENV */
  1522. END_OF_FILE
  1523. if test 5242 -ne `wc -c <'sysdep.c'`; then
  1524.     echo shar: \"'sysdep.c'\" unpacked with wrong size!
  1525. fi
  1526. # end of 'sysdep.c'
  1527. fi
  1528. if test -f 'uucp.c' -a "${1}" != "-c" ; then 
  1529.   echo shar: Will not clobber existing file \"'uucp.c'\"
  1530. else
  1531. echo shar: Extracting \"'uucp.c'\" \(3132 characters\)
  1532. sed "s/^X//" >'uucp.c' <<'END_OF_FILE'
  1533. X/* $Header: uucp.c,v 1.1 88/06/06 09:39:42 chip Exp $
  1534. X *
  1535. X * Handle mail destined for other hosts via UUCP.
  1536. X * Deliver is intended as a very low-level program, so we don't
  1537. X * do anything fancy here.  We just hand the message to uux.
  1538. X *
  1539. X * $Log:    uucp.c,v $
  1540. X * Revision 1.1  88/06/06  09:39:42  chip
  1541. X * Initial revision
  1542. X * 
  1543. X */
  1544. X
  1545. X#include "deliver.h"
  1546. X#include <sys/types.h>
  1547. X#include <sys/stat.h>
  1548. X
  1549. X/*
  1550. X * Local functions.
  1551. X */
  1552. X
  1553. Xstatic  int     uucp_copy();
  1554. X
  1555. X/*----------------------------------------------------------------------
  1556. X * Send mail to UUCP addresses (if any).
  1557. X * This is a simple implementation: invoke uux once per address.
  1558. X */
  1559. X
  1560. Xuucp_deliver()
  1561. X{
  1562. X    struct stat st;
  1563. X    DEST    *d;
  1564. X    char    *uux;
  1565. X    static char uux1[] = "/bin/uux";
  1566. X    static char uux2[] = "/usr/bin/uux";
  1567. X
  1568. X    if (stat(uux1, &st) == 0)
  1569. X        uux = uux1;
  1570. X    else if (stat(uux2, &st) == 0)
  1571. X        uux = uux2;
  1572. X    else
  1573. X    {
  1574. X        error("can't find uux!?\n");
  1575. X        return;
  1576. X    }
  1577. X
  1578. X    for (d = first_dest(); d; d = next_dest(d))
  1579. X    {
  1580. X        FILE    *uux_fp;
  1581. X        char    *bang;
  1582. X        char    *av[5];
  1583. X        char    rmail[40];
  1584. X        char    who[BUFSIZ];
  1585. X
  1586. X        if (d->class != CL_UUCP || d->state != ST_WORKING)
  1587. X            continue;
  1588. X
  1589. X        if (printaddrs)
  1590. X            (void) printf("%s\n", d->name);
  1591. X
  1592. X        if (dryrun)
  1593. X        {
  1594. X            d->state = ST_DONE;
  1595. X            continue;
  1596. X        }
  1597. X
  1598. X        bang = strchr(d->name, '!');
  1599. X        *bang = 0;
  1600. X        (void) sprintf(rmail, "%s!rmail", d->name);
  1601. X        *bang++ = '!';
  1602. X        (void) sprintf(who, "(%s)", bang);
  1603. X
  1604. X        av[0] = "uux";
  1605. X        av[1] = "-";
  1606. X        av[2] = rmail;
  1607. X        av[3] = who;
  1608. X        av[4] = NULL;
  1609. X        if ((uux_fp = ct_popenv(eff_ct, uux, av, "w")) == NULL)
  1610. X            continue;
  1611. X
  1612. X        if (uucp_copy(uux_fp) < 0)
  1613. X        {
  1614. X            d->state = ST_ERROR;
  1615. X            d->error = "Error piping to uux";
  1616. X        }
  1617. X
  1618. X        if (ct_pclose(uux_fp))
  1619. X        {
  1620. X            /* Overrides any problems with uucp_copy() */
  1621. X
  1622. X            d->state = ST_ERROR;
  1623. X            d->error = "UUCP not available to that host";
  1624. X        }
  1625. X        else
  1626. X            d->state = ST_DONE;
  1627. X    }
  1628. X}
  1629. X
  1630. X/*----------------------------------------------------------------------
  1631. X * Write the message for UUCP transmission to the given file.
  1632. X */
  1633. X
  1634. Xstatic int
  1635. Xuucp_copy(ofp)
  1636. XFILE    *ofp;
  1637. X{
  1638. X    FILE    *ifp;
  1639. X    char    *p;
  1640. X    register int c;
  1641. X    int     fd;
  1642. X    char    buf[BUFSIZ];
  1643. X
  1644. X    if ((fd = dup(tfd[T_HEADER])) == -1)
  1645. X    {
  1646. X        syserr("can't dup header fd");
  1647. X        return -1;
  1648. X    }
  1649. X    (void) lseek(fd, 0L, 0);
  1650. X    if ((ifp = fdopen(fd, "r")) == NULL)
  1651. X    {
  1652. X        error("can't fdopen header fd");
  1653. X        return -1;
  1654. X    }
  1655. X
  1656. X    /*
  1657. X     * Copy the header, but tack "remote from" onto the end of the
  1658. X     * From_ line.  (If it weren't for dealing with the From_ line,
  1659. X     * I'd skip stream I/O altogether and use read/write.  Maybe
  1660. X     * I should save the length of the From_ line when I copy it...)
  1661. X     */
  1662. X
  1663. X    (void) fgets(buf, GETSIZE(buf), ifp);
  1664. X    if ((p = strchr(buf, '\n')) != NULL)
  1665. X        *p = 0;
  1666. X    (void) fprintf(ofp, "%s remote from %s\n", buf, hostname);
  1667. X
  1668. X    while ((c = getc(ifp)) != EOF)
  1669. X        (void) putc(c, ofp);
  1670. X
  1671. X    (void) fclose(ifp);
  1672. X
  1673. X    /*
  1674. X     * Copy the body
  1675. X     */
  1676. X
  1677. X    if ((fd = dup(tfd[T_BODY])) == -1)
  1678. X    {
  1679. X        syserr("can't dup body fd");
  1680. X        return -1;
  1681. X    }
  1682. X    (void) lseek(fd, 0L, 0);
  1683. X    if ((ifp = fdopen(fd, "r")) == NULL)
  1684. X    {
  1685. X        error("can't fdopen body fd");
  1686. X        (void) close(fd);
  1687. X        return -1;
  1688. X    }
  1689. X
  1690. X    while ((c = getc(ifp)) != EOF)
  1691. X        (void) putc(c, ofp);
  1692. X
  1693. X    (void) fclose(ifp);
  1694. X    return 0;
  1695. X}
  1696. END_OF_FILE
  1697. if test 3132 -ne `wc -c <'uucp.c'`; then
  1698.     echo shar: \"'uucp.c'\" unpacked with wrong size!
  1699. fi
  1700. # end of 'uucp.c'
  1701. fi
  1702. echo shar: End of shell archive.
  1703. exit 0
  1704.  
  1705.